# 基于高德搭建选址组件
先来看看效果
主要有几个功能:
- 打开时定位
- 如果有传入地址则跳转至该地址
- 选省市区,然后地图跳到选择区域并画出来
- 启动拖动选址功能
- 根据选址自动变换省市区及详细地址
# 初始化高德
# 挂载高德js
这里选择的是回调的方法,密钥自行去官网获取
async beforeCreate () {
window.onLoad = () => {
this.init()
}
const url = `https://webapi.amap.com/maps?v=2.0&key=${AMapKey}&callback=onLoad`
const jsapi = document.createElement('script')
jsapi.charset = 'utf-8'
jsapi.src = url
document.head.appendChild(jsapi)
},
在主js加载完成后加载样式的js,并初始化地图实例
async init () {
await this.utils.getScript(`//webapi.amap.com/ui/1.1/main.js`)
this.initAMap()
},
# 初始化主逻辑
从父组件传入的信息中获取经纬度、城市等信息
- 如果没经纬度则走选地址
- 先初始化一个地图实例
- 如果没有需要移动去的城市id,则调用定位,显示定位动画
- 定位完成后纪录经纬度,并根据经纬度查找中文地址以及找出公司自己的城市id
- 有经纬度则初始化时传入,并渲染一个标记出来,下文有帖代码
- 然后初始化一些插件
initAMap () {
this.latitude = this.mapConfig.latitude
this.longitude = this.mapConfig.longitude
this.searchText = this.mapConfig.city
if (window.AMap) {
const AMap = window.AMap
if (!this.mapConfig.latitude || !this.mapConfig.longitude) {
// 没经纬度表示是选地址
this.map = new AMap.Map('map', {
resizeEnable: true,
zoom: 14,
viewMode: '3D'
})
if (!this.mapConfig.moveToAreaId) {
this.showLoading = true
AMap.plugin('AMap.Geolocation', () => {
let geolocation = new AMap.Geolocation({
enableHighAccuracy: true, // 是否使用高精度定位,默认:true
timeout: 10000, // 超过10秒后停止定位,默认:无穷大
maximumAge: 0, // 定位结果缓存0毫秒,默认:0
convert: true, // 自动偏移坐标,偏移后的坐标为高德坐标,默认:true
showButton: true, // 显示定位按钮,默认:true
buttonPosition: 'LB', // 定位按钮停靠位置,默认:'LB',左下角
buttonOffset: new AMap.Pixel(100, 200), // 定位按钮与设置的停靠位置的偏移量,默认:Pixel(10, 20)
showMarker: true, // 定位成功后在定位到的位置显示点标记,默认:true
showCircle: true, // 定位成功后用圆圈表示定位精度范围,默认:true
panToLocation: true, // 定位成功后将定位到的位置作为地图中心点,默认:true
zoomToAccuracy: true // 定位成功后调整地图视野范围使定位位置及精度范围视野内可见,默认:false
})
this.map.addControl(geolocation)
geolocation.getCurrentPosition((status, result) => {
if (status === 'complete') {
this.onComplete(result)
} else {
this.onError(result)
}
this.showLoading = false
})
})
}
} else {
// 有经纬度表示是显示该地址
this.map = new AMap.Map('map', {
center: [this.mapConfig.longitude, this.mapConfig.latitude],
resizeEnable: true,
zoom: 14,
viewMode: '3D'
})
this.$nextTick(() => {
this.renderMarker([this.mapConfig.longitude, this.mapConfig.latitude])
})
}
this.setMapPlugin(AMap)
// 选地址时才绑定poi搜索
if (this.mapConfig.showSearchBox) {
this.bindDragMapFunc(!this.mapConfig.moveToAreaId)
this.bindEvent()
// this.bindClick(this.map)
}
if (this.mapConfig.moveToAreaId) {
this.$emit('areaChange', this.findCityNameByAreaId(this.mapConfig.areaId), this.mapConfig.areaId, '', true)
}
}
},
# 生成marker标记
/**
* 生成marker标记
* @param lngLat
*/
renderMarker (lngLat) {
const AMap = window.AMap
/* eslint-disable */
if (AMap && this.map) {
this.positionPicker && this.positionPicker.stop()
this.marker && this.map.remove(this.marker)
// const icon = new AMap.Icon({
// size: new AMap.Size(30, 40), // 图标尺寸
// image: '//image.greenplayer.cn/share/img/icon/icon_court.svg', // Icon的图像
// // imageOffset: new AMap.Pixel(0, -60), // 图像相对展示区域的偏移量,适于雪碧图等
// imageSize: new AMap.Size(30, 40) // 根据所设置的大小拉伸或压缩图片
// });
this.marker = new AMap.Marker({
map: this.map,
position: lngLat
// icon: icon
})
// this.map.setFitView()
this.map.setCenter(lngLat)
this.map.on('touchstart', () => {
this.positionPicker && !this.positionPicker.started && this.positionPicker.start()
this.map.clearEvents('touchstart')
})
}
},
# 初始化插件
setMapPlugin (AMap) {
let plugins = ['AMap.ToolBar', 'AMap.Geolocation', 'AMap.ControlBar', 'AMap.DistrictSearch']
AMap.plugin(plugins, () => {
this.map.addControl(new AMap.ToolBar())
this.map.addControl(new AMap.Geolocation({
position: {
left: '0.4rem',
bottom: '0.4rem'
}
}))
this.map.addControl(new AMap.ControlBar({
position: {
right: '0.3rem',
top: '1.2rem'
},
showControlButton: true // 是否显示倾斜、旋转按钮。默认为 true
}))
})
},
# 启用拖动选点
/**
* 拖动选点
*/
bindDragMapFunc (setInfo = true) {
this.poiPicker = null
const AMapUI = window.AMapUI
// 加载PositionPicker,loadUI的路径参数为模块名中 'ui/' 之后的部分
AMapUI.loadUI(['misc/PositionPicker'], (PositionPicker) => {
this.positionPicker = new PositionPicker({
mode: 'dragMap', // 设定为拖拽地图模式,可选'dragMap'、'dragMarker',默认为'dragMap'
map: this.map // 依赖地图对象
})
this.positionPicker.on('success', (positionResult) => {
console.log('positionResult', positionResult)
if (setInfo) {
this.getPosition(positionResult.position)
this.lngGetNames(positionResult.regeocode, true)
}
// this.renderMarker([positionResult.position.lng, positionResult.position.lat])
})
this.positionPicker.on('fail', (positionResult) => {
// 海上或海外无法获得地址信息
})
this.positionPicker.start()
if (setInfo) {
}
})
},
# 监听事件
主要用在搜索后,拖动地图或点击等事件中隐藏搜索列表
/**
* 地图事件,如果有显示搜索列表,则隐藏
*/
bindEvent () {
const eventList = ['click', 'mapmove', 'mousewheel']
eventList.forEach(item => {
this.map.on(item, () => {
if (this.showSearchList) this.showSearchList = false
})
})
this.$on('hook:beforeDestroy', () => {
eventList.forEach(item => {
this.map.clearEvents(item)
})
})
},
# 画出所选行政区
- 没有初始化时先初始化
- 根据自家城市选择器传来的地区,获取区域级别(省市区),并给行政区搜索插件设置上
- 搜索传入的最小的行政区,有结果后清除上一次画的区域
- 这里注意返回结果可能存在多个,于是根据选的区域找真实的那个
- 画出区域
/**
* 选择城市后打标记并移过去
*/
mapToChooseCity () {
this.positionPicker && this.positionPicker.stop()
const AMap = window.AMap
if (!this.district) {
var opts = {
subdistrict: 0, // 获取边界不需要返回下级行政区
extensions: 'all', // 返回行政区边界坐标组等具体信息
level: 'district' // 查询行政级别为 市
}
this.district = new AMap.DistrictSearch(opts)
}
const cityList = this.mapConfig.areaName.split(' ').filter(item => item)
const addressLevel = ['province', 'city', 'district']
const address = cityList[cityList.length - 1]
// 行政区查询
this.district.setLevel(addressLevel[cityList.length - 1])
this.district.search(address, (status, result) => {
this.map.remove(this.polygons)// 清除上次结果
this.polygons = []
const list = result.districtList
if (list) {
let findItemIndex = 0
if (list.length > 0) {
// 全国名字有多个时,查具体地址,然后比对省,找出对的
let promiseList = []
list.forEach(item => {
promiseList.push(this.findItemDetailAddress(item))
})
Promise.all(promiseList).then(x => {
const realCityIndex = x.findIndex(city => {
return city.regeocode.addressComponent.province.includes(cityList[0])
})
if (realCityIndex !== -1) {
findItemIndex = realCityIndex
}
this.drawCityArea(result.districtList[findItemIndex])
})
} else {
this.drawCityArea(result.districtList[findItemIndex])
}
}
})
},
画区域很简单,官网直接有例子的
地图移动有个过程,于是延迟再执行拖动选点
drawCityArea (findItem) {
const AMap = window.AMap
var bounds = findItem.boundaries
if (bounds) {
for (var i = 0, l = bounds.length; i < l; i++) {
// 生成行政区划polygon
this.polygon = new AMap.Polygon({
strokeWeight: 1,
path: bounds[i],
fillOpacity: 0.4,
fillColor: '#80d8ff',
strokeColor: '#0091ea'
})
this.polygons.push(this.polygon)
}
}
this.map.add(this.polygons)
this.map.setFitView(this.polygons)// 视口自适应
setTimeout(() => {
this.positionPicker.start()
}, 1500)
},
← 开篇 拦截复制事件并替换图片url →